<?php

namespace Pinenut\Model2\Embedded;

use Pinenut\Model2\Updater;
use Pinenut\Model2\Embedded;

class ReferenceContainer extends Embedded implements \ArrayAccess, \Iterator, \Countable {
	/**
	 * Базовый тип связи
	 *
	 * @var \Pinenut\Model2\Embedded\Reference
	 */
	protected $_reference;
	
	/**
	 * Контейнер, или одна связь или множество
	 *
	 * @var \Pinenut\Model2\Reference | \Pinenut\Model2\Reference[]
	 */
	protected $_container = array ();
	
	/**
	 * имя класса на который указывает ссылка
	 *
	 * @var \Pinenut\Model2
	 */
	protected $_referedClass;
	
	/**
	 * имя поля обратной ссылки
	 */
	protected $_referedField;
	
	/**
	 * Установка параметров ссылки при определении структуры модели
	 *
	 * @param \Pinenut\Model2\Embedded $reference        	
	 * @param string $className        	
	 * @param string $fieldName        	
	 */
	function __construct(Embedded $parent, $field, array $params = array()) {
		parent::__construct ( $parent, $field );
		
		$this->_parent = $parent;
		$this->_field = $field;

		$refParams = [];
		$i = 0;
		foreach ($params as $key=>$val) {
			if (is_string($key)) {
				$refParams[$key] = $val;
			} else {
				switch ($i++) {
					case 0: $referenceClass = $val; break;
					case 1: $this->_referedClass = $val; break;
					case 2: $this->_referedField = $val; break;
					default: $refParams[$key] = $val;
				}
			}
		}
						
		$this->_reference = new $referenceClass ( $this, $field, $refParams );
	}
	function getNewReference($ref = null) {
		$reference = clone $this->_reference;
		if (null !== $ref) {
			$reference->_ref = $ref;
		}
		return $reference;
	}
	function getReferedClass() {
		return $this->_referedClass;
	}
	
	// ArrayAccess
	/**
	 * При установки значения ничего не делаем, т.е.
	 * доступ возможен только к уже готовым связям
	 */
	public function offsetSet($offset, $value) {
	}
	
	/**
	 * Проверяем существование связи
	 * В простом случае - только у нас, а для связей хранящихся не у нас,
	 * но на нас - должны проверить обратную ссылку
	 */
	public function offsetExists($offset) {
		return isset ( $this->_container [( string ) $offset] );
	}
	
	/**
	 * Удаляем связь
	 */
	public function offsetUnset($offset) {
		unset ( $this->_container [( string ) $offset] );
	}
	
	/**
	 * Возвращаем связь, если не существует - создаём
	 */
	public function offsetGet($offset) {
		$id = ( string ) $offset;
		// ищем связь в контейнере,
		if (! isset ( $this [$id] )) {
			// добавляем связь
			$this->_container [$id] = $this->getNewReference ( $id );
		}
		// возвращаем её
		return $this->_container [$id];
	}
	
	// Iterator
	function rewind() {
		return reset ( $this->_container );
	}
	function current() {
		return current ( $this->_container );
	}
	function key() {
		return key ( $this->_container );
	}
	function next() {
		return next ( $this->_container );
	}
	function valid() {
		return key ( $this->_container ) !== null;
	}
	function isEmpty() {
		return empty ( $this->_container );
	}
	function count() {
		return count ( $this->_container );
	}
	public function toArray() {
		$data = [ ];
		foreach ( $this->_container as $ref ) {
			if (method_exists ( $ref, 'toArray' )) {
				$data [] = $ref->toArray ();
			}
		}
		return $data;
	}
	public function getIds() {
		$data = [ ];
		foreach ( $this->_container as $ref ) {
			$data [] = ( string ) $ref;
		}
		return $data;
	}
	
}